package com.wzx.core.aop.invoke;

import com.wzx.core.aop.annotaction.After;
import com.wzx.core.aop.annotaction.Before;
import com.wzx.core.aop.annotaction.Running;
import com.wzx.core.aop.annotaction.Throwing;
import com.wzx.core.ioc.anootaction.Transactional;
import com.wzx.core.ioc.context.AbstractApplicationContext;
import com.wzx.core.ioc.transaction.TransactionManager;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class TransactionInvocation {

    private AbstractApplicationContext context;


    private Method before;
    private Method after;
    private Method running;
    private Method throwing;


    public TransactionInvocation(AbstractApplicationContext context) {
        this.context = context;
        try {
            List<Method> methodList = Arrays.asList(this.getClass().getDeclaredMethods());
            String[] methods = new String[]{"before", "after", "running", "throwing"};
            for (String methodName : methods) {
                Method method = methodList.stream().filter(item -> item.getName().equals(methodName)).findFirst().get();
                Field declaredField = this.getClass().getDeclaredField(methodName);
                declaredField.setAccessible(true);
                declaredField.set(this, method);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Before()
    public void before(JoinPoint joinPoint) {
        Transactional transactional = Optional
                .ofNullable(joinPoint.getMethod().getAnnotation(Transactional.class))
                .orElse(joinPoint.getOrigin().getClass().getAnnotation(Transactional.class));
        if (transactional == null) {
            // 不开启事务
            return;
        }
        try {
            Connection connection = TransactionManager.conn.get();
            if (connection == null) {
                connection = context.getBean("connection");
                TransactionManager.conn.set(connection);
            }
            connection.setAutoCommit(false);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    @After()
    public void after(JoinPoint joinPoint) {
        try {
            TransactionManager.conn.get().commit();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    @Running()
    public void running(JoinPoint joinPoint) {
        try {
            TransactionManager.conn.get().commit();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    @Throwing()
    public void throwing(JoinPoint joinPoint) {
        try {
            TransactionManager.conn.get().rollback();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }


    public Method getBefore() {
        return before;
    }

    public Method getAfter() {
        return after;
    }

    public Method getRunning() {
        return running;
    }

    public Method getThrowing() {
        return throwing;
    }
}
